﻿namespace Pathfinding
{
    using Pathfinding.Serialization;
    using Pathfinding.Serialization.JsonFx;
    using Pathfinding.Util;
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using UnityEngine;

    [JsonOptIn]
    public class GridGraph : NavGraph, IUpdatableGraph, IRaycastableGraph
    {
        [JsonMember]
        public float aspectRatio = 1f;
        [JsonMember]
        public float autoLinkDistLimit = 10f;
        [JsonMember]
        public bool autoLinkGrids;
        public Bounds bounds;
        public Matrix4x4 boundsMatrix;
        public Matrix4x4 boundsMatrix2;
        [JsonMember]
        public Vector3 center;
        [JsonMember]
        public GraphCollision collision;
        [NonSerialized]
        protected int[] corners;
        [JsonMember]
        public bool cutCorners = true;
        public int depth;
        [JsonMember]
        public int erodeIterations;
        [JsonMember]
        public int erosionFirstTag = 1;
        [JsonMember]
        public bool erosionUseTags;
        public const int getNearestForceOverlap = 2;
        [JsonMember]
        public float maxClimb = 0.4f;
        [JsonMember]
        public int maxClimbAxis = 1;
        [JsonMember]
        public float maxSlope = 90f;
        [NonSerialized]
        public readonly uint[] neighbourCosts = new uint[8];
        [NonSerialized]
        public readonly int[] neighbourOffsets = new int[8];
        [JsonMember]
        public NumNeighbours neighbours = NumNeighbours.Eight;
        [NonSerialized]
        public readonly int[] neighbourXOffsets = new int[8];
        [NonSerialized]
        public readonly int[] neighbourZOffsets = new int[8];
        public GridNode[] nodes;
        [JsonMember]
        public float nodeSize = 1f;
        [JsonMember]
        public bool penaltyAngle;
        [JsonMember]
        public float penaltyAngleFactor = 100f;
        [JsonMember]
        public bool penaltyPosition;
        [JsonMember]
        public float penaltyPositionFactor = 1f;
        [JsonMember]
        public float penaltyPositionOffset;
        [JsonMember]
        public Vector3 rotation;
        public int scans;
        public Vector2 size;
        [JsonMember]
        public TextureData textureData = new TextureData();
        [JsonMember]
        public Vector2 unclampedSize = new Vector2(10f, 10f);
        public int width;

        public GridGraph()
        {
            this.nodeSize = 1f;
            this.collision = new GraphCollision();
        }

        public static void CalculateConnections(GridNode node)
        {
            GridGraph graph = AstarData.GetGraph(node) as GridGraph;
            if (graph != null)
            {
                int nodeInGridIndex = node.NodeInGridIndex;
                int x = nodeInGridIndex % graph.width;
                int z = nodeInGridIndex / graph.width;
                graph.CalculateConnections(graph.nodes, x, z, node);
            }
        }

        public virtual void CalculateConnections(GridNode[] nodes, int x, int z, GridNode node)
        {
            node.ResetConnectionsInternal();
            if (node.Walkable)
            {
                int nodeInGridIndex = node.NodeInGridIndex;
                if (this.corners == null)
                {
                    this.corners = new int[4];
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        this.corners[i] = 0;
                    }
                }
                int index = 0;
                int num4 = 3;
                while (index < 4)
                {
                    int num5 = x + this.neighbourXOffsets[index];
                    int num6 = z + this.neighbourZOffsets[index];
                    if ((((num5 >= 0) && (num6 >= 0)) && (num5 < this.width)) && (num6 < this.depth))
                    {
                        GridNode node2 = nodes[nodeInGridIndex + this.neighbourOffsets[index]];
                        if (this.IsValidConnection(node, node2))
                        {
                            node.SetConnectionInternal(index, true);
                            this.corners[index]++;
                            this.corners[num4]++;
                        }
                        else
                        {
                            node.SetConnectionInternal(index, false);
                        }
                    }
                    num4 = index;
                    index++;
                }
                if (this.neighbours == NumNeighbours.Eight)
                {
                    if (this.cutCorners)
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            if (this.corners[j] >= 1)
                            {
                                int num8 = x + this.neighbourXOffsets[j + 4];
                                int num9 = z + this.neighbourZOffsets[j + 4];
                                if ((((num8 >= 0) && (num9 >= 0)) && (num8 < this.width)) && (num9 < this.depth))
                                {
                                    GridNode node3 = nodes[nodeInGridIndex + this.neighbourOffsets[j + 4]];
                                    node.SetConnectionInternal(j + 4, this.IsValidConnection(node, node3));
                                }
                            }
                        }
                    }
                    else
                    {
                        for (int k = 0; k < 4; k++)
                        {
                            if (this.corners[k] == 2)
                            {
                                GridNode node4 = nodes[nodeInGridIndex + this.neighbourOffsets[k + 4]];
                                node.SetConnectionInternal(k + 4, this.IsValidConnection(node, node4));
                            }
                        }
                    }
                }
            }
        }

        public GraphUpdateThreading CanUpdateAsync(GraphUpdateObject o)
        {
            return GraphUpdateThreading.UnityThread;
        }

        public bool CheckConnection(GridNode node, int dir)
        {
            if (this.neighbours == NumNeighbours.Eight)
            {
                return this.HasNodeConnection(node, dir);
            }
            int num = ((dir - 4) - 1) & 3;
            int num2 = ((dir - 4) + 1) & 3;
            if (!this.HasNodeConnection(node, num) || !this.HasNodeConnection(node, num2))
            {
                return false;
            }
            GridNode node2 = this.nodes[node.NodeInGridIndex + this.neighbourOffsets[num]];
            GridNode node3 = this.nodes[node.NodeInGridIndex + this.neighbourOffsets[num2]];
            if (!node2.Walkable || !node3.Walkable)
            {
                return false;
            }
            return (this.HasNodeConnection(node3, num) && this.HasNodeConnection(node2, num2));
        }

        public override void DeserializeExtraInfo(GraphSerializationContext ctx)
        {
            int num = ctx.reader.ReadInt32();
            if (num == -1)
            {
                this.nodes = null;
            }
            else
            {
                this.nodes = new GridNode[num];
                for (int i = 0; i < this.nodes.Length; i++)
                {
                    this.nodes[i] = new GridNode(base.active);
                    this.nodes[i].DeserializeNode(ctx);
                }
            }
        }

        public virtual void ErodeWalkableArea()
        {
            this.ErodeWalkableArea(0, 0, this.Width, this.Depth);
        }

        public virtual void ErodeWalkableArea(int xmin, int zmin, int xmax, int zmax)
        {
            xmin = (xmin >= 0) ? ((xmin <= this.Width) ? xmin : this.Width) : 0;
            xmax = (xmax >= 0) ? ((xmax <= this.Width) ? xmax : this.Width) : 0;
            zmin = (zmin >= 0) ? ((zmin <= this.Depth) ? zmin : this.Depth) : 0;
            zmax = (zmax >= 0) ? ((zmax <= this.Depth) ? zmax : this.Depth) : 0;
            if (!this.erosionUseTags)
            {
                for (int i = 0; i < this.erodeIterations; i++)
                {
                    for (int j = zmin; j < zmax; j++)
                    {
                        for (int m = xmin; m < xmax; m++)
                        {
                            GridNode node = this.nodes[(j * this.Width) + m];
                            if (node.Walkable)
                            {
                                bool flag = false;
                                for (int n = 0; n < 4; n++)
                                {
                                    if (!this.HasNodeConnection(node, n))
                                    {
                                        flag = true;
                                        break;
                                    }
                                }
                                if (flag)
                                {
                                    node.Walkable = false;
                                }
                            }
                        }
                    }
                    for (int k = zmin; k < zmax; k++)
                    {
                        for (int num6 = xmin; num6 < xmax; num6++)
                        {
                            GridNode node2 = this.nodes[(k * this.Width) + num6];
                            this.CalculateConnections(this.nodes, num6, k, node2);
                        }
                    }
                }
            }
            else if ((this.erodeIterations + this.erosionFirstTag) > 0x1f)
            {
                Debug.LogError(string.Concat(new object[] { "Too few tags available for ", this.erodeIterations, " erode iterations and starting with tag ", this.erosionFirstTag, " (erodeIterations+erosionFirstTag > 31)" }));
            }
            else if (this.erosionFirstTag <= 0)
            {
                Debug.LogError("First erosion tag must be greater or equal to 1");
            }
            else
            {
                for (int num7 = 0; num7 < this.erodeIterations; num7++)
                {
                    for (int num8 = zmin; num8 < zmax; num8++)
                    {
                        for (int num9 = xmin; num9 < xmax; num9++)
                        {
                            GridNode node3 = this.nodes[(num8 * this.width) + num9];
                            if ((node3.Walkable && (node3.Tag >= this.erosionFirstTag)) && (node3.Tag < (this.erosionFirstTag + num7)))
                            {
                                for (int num10 = 0; num10 < 4; num10++)
                                {
                                    GridNode nodeConnection = this.GetNodeConnection(node3, num10);
                                    if (nodeConnection != null)
                                    {
                                        uint tag = nodeConnection.Tag;
                                        if ((tag > (this.erosionFirstTag + num7)) || (tag < this.erosionFirstTag))
                                        {
                                            nodeConnection.Tag = (uint) (this.erosionFirstTag + num7);
                                        }
                                    }
                                }
                                continue;
                            }
                            if (node3.Walkable && (num7 == 0))
                            {
                                bool flag2 = false;
                                for (int num12 = 0; num12 < 4; num12++)
                                {
                                    if (!this.HasNodeConnection(node3, num12))
                                    {
                                        flag2 = true;
                                        break;
                                    }
                                }
                                if (flag2)
                                {
                                    node3.Tag = (uint) (this.erosionFirstTag + num7);
                                }
                            }
                        }
                    }
                }
            }
        }

        public void GenerateMatrix()
        {
            this.size = this.unclampedSize;
            this.size.x *= Mathf.Sign(this.size.x);
            this.size.y *= Mathf.Sign(this.size.y);
            this.nodeSize = Mathf.Clamp(this.nodeSize, this.size.x / 1024f, float.PositiveInfinity);
            this.nodeSize = Mathf.Clamp(this.nodeSize, this.size.y / 1024f, float.PositiveInfinity);
            this.size.x = (this.size.x >= this.nodeSize) ? this.size.x : this.nodeSize;
            this.size.y = (this.size.y >= this.nodeSize) ? this.size.y : this.nodeSize;
            this.boundsMatrix.SetTRS(this.center, Quaternion.Euler(this.rotation), new Vector3(this.aspectRatio, 1f, 1f));
            this.width = Mathf.FloorToInt(this.size.x / this.nodeSize);
            this.depth = Mathf.FloorToInt(this.size.y / this.nodeSize);
            if (Mathf.Approximately(this.size.x / this.nodeSize, (float) Mathf.CeilToInt(this.size.x / this.nodeSize)))
            {
                this.width = Mathf.CeilToInt(this.size.x / this.nodeSize);
            }
            if (Mathf.Approximately(this.size.y / this.nodeSize, (float) Mathf.CeilToInt(this.size.y / this.nodeSize)))
            {
                this.depth = Mathf.CeilToInt(this.size.y / this.nodeSize);
            }
            base.SetMatrix(Matrix4x4.TRS(this.boundsMatrix.MultiplyPoint3x4((Vector3) (-new Vector3(this.size.x, 0f, this.size.y) * 0.5f)), Quaternion.Euler(this.rotation), new Vector3(this.nodeSize * this.aspectRatio, 1f, this.nodeSize)));
        }

        public void GetBoundsMinMax(Bounds b, Matrix4x4 matrix, out Vector3 min, out Vector3 max)
        {
            Vector3[] vectorArray = new Vector3[] { matrix.MultiplyPoint3x4(b.center + new Vector3(b.extents.x, b.extents.y, b.extents.z)), matrix.MultiplyPoint3x4(b.center + new Vector3(b.extents.x, b.extents.y, -b.extents.z)), matrix.MultiplyPoint3x4(b.center + new Vector3(b.extents.x, -b.extents.y, b.extents.z)), matrix.MultiplyPoint3x4(b.center + new Vector3(b.extents.x, -b.extents.y, -b.extents.z)), matrix.MultiplyPoint3x4(b.center + new Vector3(-b.extents.x, b.extents.y, b.extents.z)), matrix.MultiplyPoint3x4(b.center + new Vector3(-b.extents.x, b.extents.y, -b.extents.z)), matrix.MultiplyPoint3x4(b.center + new Vector3(-b.extents.x, -b.extents.y, b.extents.z)), matrix.MultiplyPoint3x4(b.center + new Vector3(-b.extents.x, -b.extents.y, -b.extents.z)) };
            min = vectorArray[0];
            max = vectorArray[0];
            for (int i = 1; i < 8; i++)
            {
                min = Vector3.Min(min, vectorArray[i]);
                max = Vector3.Max(max, vectorArray[i]);
            }
        }

        public uint GetConnectionCost(int dir)
        {
            return this.neighbourCosts[dir];
        }

        public override NNInfo GetNearest(Vector3 position, NNConstraint constraint, GraphNode hint)
        {
            if ((this.nodes == null) || ((this.depth * this.width) != this.nodes.Length))
            {
                return new NNInfo();
            }
            position = this.inverseMatrix.MultiplyPoint3x4(position);
            float f = position.x - 0.5f;
            float num2 = position.z - 0.5f;
            int num3 = Mathf.Clamp(Mathf.RoundToInt(f), 0, this.width - 1);
            int num4 = Mathf.Clamp(Mathf.RoundToInt(num2), 0, this.depth - 1);
            NNInfo info = new NNInfo(this.nodes[(num4 * this.width) + num3]);
            float y = this.inverseMatrix.MultiplyPoint3x4((Vector3) this.nodes[(num4 * this.width) + num3].position).y;
            info.clampedPosition = this.matrix.MultiplyPoint3x4(new Vector3(Mathf.Clamp(f, num3 - 0.5f, num3 + 0.5f) + 0.5f, y, Mathf.Clamp(num2, num4 - 0.5f, num4 + 0.5f) + 0.5f));
            return info;
        }

        public override NNInfo GetNearestForce(Vector3 position, NNConstraint constraint)
        {
            if ((this.nodes == null) || ((this.depth * this.width) != this.nodes.Length))
            {
                return new NNInfo();
            }
            Vector3 vector = position;
            position = this.inverseMatrix.MultiplyPoint3x4(position);
            float f = position.x - 0.5f;
            float num2 = position.z - 0.5f;
            int num3 = Mathf.Clamp(Mathf.RoundToInt(f), 0, this.width - 1);
            int num4 = Mathf.Clamp(Mathf.RoundToInt(num2), 0, this.depth - 1);
            GridNode node = this.nodes[num3 + (num4 * this.width)];
            GridNode node2 = null;
            float positiveInfinity = float.PositiveInfinity;
            int num6 = 2;
            Vector3 zero = Vector3.zero;
            NNInfo info = new NNInfo(null);
            if (constraint.Suitable(node))
            {
                node2 = node;
                Vector3 vector3 = ((Vector3) node2.position) - vector;
                positiveInfinity = vector3.sqrMagnitude;
                float y = this.inverseMatrix.MultiplyPoint3x4((Vector3) node.position).y;
                zero = this.matrix.MultiplyPoint3x4(new Vector3(Mathf.Clamp(f, num3 - 0.5f, num3 + 0.5f) + 0.5f, y, Mathf.Clamp(num2, num4 - 0.5f, num4 + 0.5f) + 0.5f));
            }
            if (node2 != null)
            {
                info.node = node2;
                info.clampedPosition = zero;
                if (num6 == 0)
                {
                    return info;
                }
                num6--;
            }
            float num8 = !constraint.constrainDistance ? float.PositiveInfinity : AstarPath.active.maxNearestNodeDistance;
            float num9 = num8 * num8;
            int num10 = 1;
            while (true)
            {
                if ((this.nodeSize * num10) > num8)
                {
                    info.node = node2;
                    info.clampedPosition = zero;
                    return info;
                }
                bool flag = false;
                int num11 = num3;
                int num12 = num4 + num10;
                int num13 = num12 * this.width;
                for (num11 = num3 - num10; num11 <= (num3 + num10); num11++)
                {
                    if ((((num11 >= 0) && (num12 >= 0)) && (num11 < this.width)) && (num12 < this.depth))
                    {
                        flag = true;
                        if (constraint.Suitable(this.nodes[num11 + num13]))
                        {
                            Vector3 vector5 = ((Vector3) this.nodes[num11 + num13].position) - vector;
                            float sqrMagnitude = vector5.sqrMagnitude;
                            if ((sqrMagnitude < positiveInfinity) && (sqrMagnitude < num9))
                            {
                                positiveInfinity = sqrMagnitude;
                                node2 = this.nodes[num11 + num13];
                                zero = this.matrix.MultiplyPoint3x4(new Vector3(Mathf.Clamp(f, num11 - 0.5f, num11 + 0.5f) + 0.5f, this.inverseMatrix.MultiplyPoint3x4((Vector3) node2.position).y, Mathf.Clamp(num2, num12 - 0.5f, num12 + 0.5f) + 0.5f));
                            }
                        }
                    }
                }
                num12 = num4 - num10;
                num13 = num12 * this.width;
                for (num11 = num3 - num10; num11 <= (num3 + num10); num11++)
                {
                    if ((((num11 >= 0) && (num12 >= 0)) && (num11 < this.width)) && (num12 < this.depth))
                    {
                        flag = true;
                        if (constraint.Suitable(this.nodes[num11 + num13]))
                        {
                            Vector3 vector7 = ((Vector3) this.nodes[num11 + num13].position) - vector;
                            float num15 = vector7.sqrMagnitude;
                            if ((num15 < positiveInfinity) && (num15 < num9))
                            {
                                positiveInfinity = num15;
                                node2 = this.nodes[num11 + num13];
                                zero = this.matrix.MultiplyPoint3x4(new Vector3(Mathf.Clamp(f, num11 - 0.5f, num11 + 0.5f) + 0.5f, this.inverseMatrix.MultiplyPoint3x4((Vector3) node2.position).y, Mathf.Clamp(num2, num12 - 0.5f, num12 + 0.5f) + 0.5f));
                            }
                        }
                    }
                }
                num11 = num3 - num10;
                num12 = (num4 - num10) + 1;
                for (num12 = (num4 - num10) + 1; num12 <= ((num4 + num10) - 1); num12++)
                {
                    if ((((num11 >= 0) && (num12 >= 0)) && (num11 < this.width)) && (num12 < this.depth))
                    {
                        flag = true;
                        if (constraint.Suitable(this.nodes[num11 + (num12 * this.width)]))
                        {
                            Vector3 vector9 = ((Vector3) this.nodes[num11 + (num12 * this.width)].position) - vector;
                            float num16 = vector9.sqrMagnitude;
                            if ((num16 < positiveInfinity) && (num16 < num9))
                            {
                                positiveInfinity = num16;
                                node2 = this.nodes[num11 + (num12 * this.width)];
                                zero = this.matrix.MultiplyPoint3x4(new Vector3(Mathf.Clamp(f, num11 - 0.5f, num11 + 0.5f) + 0.5f, this.inverseMatrix.MultiplyPoint3x4((Vector3) node2.position).y, Mathf.Clamp(num2, num12 - 0.5f, num12 + 0.5f) + 0.5f));
                            }
                        }
                    }
                }
                num11 = num3 + num10;
                for (num12 = (num4 - num10) + 1; num12 <= ((num4 + num10) - 1); num12++)
                {
                    if ((((num11 >= 0) && (num12 >= 0)) && (num11 < this.width)) && (num12 < this.depth))
                    {
                        flag = true;
                        if (constraint.Suitable(this.nodes[num11 + (num12 * this.width)]))
                        {
                            Vector3 vector11 = ((Vector3) this.nodes[num11 + (num12 * this.width)].position) - vector;
                            float num17 = vector11.sqrMagnitude;
                            if ((num17 < positiveInfinity) && (num17 < num9))
                            {
                                positiveInfinity = num17;
                                node2 = this.nodes[num11 + (num12 * this.width)];
                                zero = this.matrix.MultiplyPoint3x4(new Vector3(Mathf.Clamp(f, num11 - 0.5f, num11 + 0.5f) + 0.5f, this.inverseMatrix.MultiplyPoint3x4((Vector3) node2.position).y, Mathf.Clamp(num2, num12 - 0.5f, num12 + 0.5f) + 0.5f));
                            }
                        }
                    }
                }
                if (node2 != null)
                {
                    if (num6 == 0)
                    {
                        info.node = node2;
                        info.clampedPosition = zero;
                        return info;
                    }
                    num6--;
                }
                if (!flag)
                {
                    info.node = node2;
                    info.clampedPosition = zero;
                    return info;
                }
                num10++;
            }
        }

        public GridNode GetNodeConnection(GridNode node, int dir)
        {
            if (!node.GetConnectionInternal(dir))
            {
                return null;
            }
            if (!node.EdgeNode)
            {
                return this.nodes[node.NodeInGridIndex + this.neighbourOffsets[dir]];
            }
            int nodeInGridIndex = node.NodeInGridIndex;
            int z = nodeInGridIndex / this.Width;
            int x = nodeInGridIndex - (z * this.Width);
            return this.GetNodeConnection(nodeInGridIndex, x, z, dir);
        }

        private GridNode GetNodeConnection(int index, int x, int z, int dir)
        {
            if (!this.nodes[index].GetConnectionInternal(dir))
            {
                return null;
            }
            int num = x + this.neighbourXOffsets[dir];
            if ((num < 0) || (num >= this.Width))
            {
                return null;
            }
            int num2 = z + this.neighbourZOffsets[dir];
            if ((num2 < 0) || (num2 >= this.Depth))
            {
                return null;
            }
            int num3 = index + this.neighbourOffsets[dir];
            return this.nodes[num3];
        }

        public Int3 GetNodePosition(int index, int yOffset)
        {
            int num = index / this.Width;
            int num2 = index - (num * this.Width);
            return (Int3) this.matrix.MultiplyPoint3x4(new Vector3(num2 + 0.5f, yOffset * 0.001f, num + 0.5f));
        }

        public override void GetNodes(GraphNodeDelegateCancelable del)
        {
            if (this.nodes != null)
            {
                for (int i = 0; (i < this.nodes.Length) && del(this.nodes[i]); i++)
                {
                }
            }
        }

        public List<GraphNode> GetNodesInArea(GraphUpdateShape shape)
        {
            return this.GetNodesInArea(shape.GetBounds(), shape);
        }

        public List<GraphNode> GetNodesInArea(Bounds b)
        {
            return this.GetNodesInArea(b, null);
        }

        private List<GraphNode> GetNodesInArea(Bounds b, GraphUpdateShape shape)
        {
            Vector3 vector;
            Vector3 vector2;
            if ((this.nodes == null) || ((this.width * this.depth) != this.nodes.Length))
            {
                return null;
            }
            List<GraphNode> list = ListPool<GraphNode>.Claim();
            this.GetBoundsMinMax(b, base.inverseMatrix, out vector, out vector2);
            int xmin = Mathf.RoundToInt(vector.x - 0.5f);
            int xmax = Mathf.RoundToInt(vector2.x - 0.5f);
            int ymin = Mathf.RoundToInt(vector.z - 0.5f);
            int ymax = Mathf.RoundToInt(vector2.z - 0.5f);
            IntRect a = new IntRect(xmin, ymin, xmax, ymax);
            IntRect rect2 = new IntRect(0, 0, this.width - 1, this.depth - 1);
            IntRect rect3 = IntRect.Intersection(a, rect2);
            for (int i = rect3.xmin; i <= rect3.xmax; i++)
            {
                for (int j = rect3.ymin; j <= rect3.ymax; j++)
                {
                    int index = (j * this.width) + i;
                    GraphNode item = this.nodes[index];
                    if (b.Contains((Vector3) item.position) && ((shape == null) || shape.Contains((Vector3) item.position)))
                    {
                        list.Add(item);
                    }
                }
            }
            return list;
        }

        public bool HasNodeConnection(GridNode node, int dir)
        {
            if (!node.GetConnectionInternal(dir))
            {
                return false;
            }
            if (!node.EdgeNode)
            {
                return true;
            }
            int nodeInGridIndex = node.NodeInGridIndex;
            int z = nodeInGridIndex / this.Width;
            int x = nodeInGridIndex - (z * this.Width);
            return this.HasNodeConnection(nodeInGridIndex, x, z, dir);
        }

        public bool HasNodeConnection(int index, int x, int z, int dir)
        {
            if (!this.nodes[index].GetConnectionInternal(dir))
            {
                return false;
            }
            int num = x + this.neighbourXOffsets[dir];
            if ((num < 0) || (num >= this.Width))
            {
                return false;
            }
            int num2 = z + this.neighbourZOffsets[dir];
            return ((num2 >= 0) && (num2 < this.Depth));
        }

        public virtual bool IsValidConnection(GridNode n1, GridNode n2)
        {
            if (!n1.Walkable || !n2.Walkable)
            {
                return false;
            }
            if ((this.maxClimb != 0f) && (Mathf.Abs((int) (n1.position[this.maxClimbAxis] - n2.position[this.maxClimbAxis])) > (this.maxClimb * 1000f)))
            {
                return false;
            }
            return true;
        }

        public bool Linecast(Vector3 _a, Vector3 _b)
        {
            GraphHitInfo info;
            return this.Linecast(_a, _b, null, out info);
        }

        public bool Linecast(Vector3 _a, Vector3 _b, GraphNode hint)
        {
            GraphHitInfo info;
            return this.Linecast(_a, _b, hint, out info);
        }

        public bool Linecast(Vector3 _a, Vector3 _b, GraphNode hint, out GraphHitInfo hit)
        {
            return this.Linecast(_a, _b, hint, out hit, null);
        }

        public bool Linecast(Vector3 _a, Vector3 _b, GraphNode hint, out GraphHitInfo hit, List<GraphNode> trace)
        {
            hit = new GraphHitInfo();
            _a = this.inverseMatrix.MultiplyPoint3x4(_a);
            _a.x -= 0.5f;
            _a.z -= 0.5f;
            _b = this.inverseMatrix.MultiplyPoint3x4(_b);
            _b.x -= 0.5f;
            _b.z -= 0.5f;
            if ((((_a.x < -0.5f) || (_a.z < -0.5f)) || ((_a.x >= (this.width - 0.5f)) || (_a.z >= (this.depth - 0.5f)))) || (((_b.x < -0.5f) || (_b.z < -0.5f)) || ((_b.x >= (this.width - 0.5f)) || (_b.z >= (this.depth - 0.5f)))))
            {
                Vector3 vector = new Vector3(-0.5f, 0f, -0.5f);
                Vector3 vector2 = new Vector3(-0.5f, 0f, this.depth - 0.5f);
                Vector3 vector3 = new Vector3(this.width - 0.5f, 0f, this.depth - 0.5f);
                Vector3 vector4 = new Vector3(this.width - 0.5f, 0f, -0.5f);
                int num = 0;
                bool intersects = false;
                Vector3 vector5 = Polygon.SegmentIntersectionPoint(vector, vector2, _a, _b, out intersects);
                if (intersects)
                {
                    num++;
                    if (!Polygon.Left(vector, vector2, _a))
                    {
                        _a = vector5;
                    }
                    else
                    {
                        _b = vector5;
                    }
                }
                vector5 = Polygon.SegmentIntersectionPoint(vector2, vector3, _a, _b, out intersects);
                if (intersects)
                {
                    num++;
                    if (!Polygon.Left(vector2, vector3, _a))
                    {
                        _a = vector5;
                    }
                    else
                    {
                        _b = vector5;
                    }
                }
                vector5 = Polygon.SegmentIntersectionPoint(vector3, vector4, _a, _b, out intersects);
                if (intersects)
                {
                    num++;
                    if (!Polygon.Left(vector3, vector4, _a))
                    {
                        _a = vector5;
                    }
                    else
                    {
                        _b = vector5;
                    }
                }
                vector5 = Polygon.SegmentIntersectionPoint(vector4, vector, _a, _b, out intersects);
                if (intersects)
                {
                    num++;
                    if (!Polygon.Left(vector4, vector, _a))
                    {
                        _a = vector5;
                    }
                    else
                    {
                        _b = vector5;
                    }
                }
                if (num == 0)
                {
                    return false;
                }
            }
            Vector3 vector6 = _b - _a;
            float magnitude = vector6.magnitude;
            if (magnitude != 0f)
            {
                float num3 = 0.2f;
                float num4 = this.nodeSize * num3;
                num4 -= this.nodeSize * 0.02f;
                vector6 = (Vector3) ((vector6 / magnitude) * num4);
                int num5 = (int) (magnitude / num4);
                Vector3 vector7 = _a + ((Vector3) ((vector6 * this.nodeSize) * 0.01f));
                GraphNode node = null;
                for (int i = 0; i <= num5; i++)
                {
                    Vector3 vector8 = vector7 + (vector6 * i);
                    int num7 = Mathf.RoundToInt(vector8.x);
                    int num8 = Mathf.RoundToInt(vector8.z);
                    num7 = (num7 >= 0) ? ((num7 < this.width) ? num7 : (this.width - 1)) : 0;
                    num8 = (num8 >= 0) ? ((num8 < this.depth) ? num8 : (this.depth - 1)) : 0;
                    GraphNode item = this.nodes[(num8 * this.width) + num7];
                    if (item != node)
                    {
                        if (!item.Walkable)
                        {
                            if (i > 0)
                            {
                                hit.point = this.matrix.MultiplyPoint3x4((vector7 + (vector6 * (i - 1))) + new Vector3(0.5f, 0f, 0.5f));
                            }
                            else
                            {
                                hit.point = this.matrix.MultiplyPoint3x4(_a + new Vector3(0.5f, 0f, 0.5f));
                            }
                            hit.origin = this.matrix.MultiplyPoint3x4(_a + new Vector3(0.5f, 0f, 0.5f));
                            hit.node = item;
                            return true;
                        }
                        if ((i > (num5 - 1)) && ((Mathf.Abs((float) (vector8.x - _b.x)) <= 0.50001f) || (Mathf.Abs((float) (vector8.z - _b.z)) <= 0.50001f)))
                        {
                            return false;
                        }
                        if (trace != null)
                        {
                            trace.Add(item);
                        }
                        node = item;
                    }
                }
            }
            return false;
        }

        public override void OnDestroy()
        {
            base.OnDestroy();
            this.RemoveGridGraphFromStatic();
        }

        public override void OnDrawGizmos(bool drawNodes)
        {
            Gizmos.matrix = this.boundsMatrix;
            Gizmos.color = Color.white;
            Gizmos.DrawWireCube(Vector3.zero, new Vector3(this.size.x, 0f, this.size.y));
            Gizmos.matrix = Matrix4x4.identity;
            if (drawNodes && ((this.nodes != null) && ((this.depth * this.width) == this.nodes.Length)))
            {
                PathHandler debugPathData = AstarPath.active.debugPathData;
                GridNode node = null;
                for (int i = 0; i < this.depth; i++)
                {
                    for (int j = 0; j < this.width; j++)
                    {
                        node = this.nodes[(i * this.width) + j];
                        if (node.Walkable)
                        {
                            Gizmos.color = this.NodeColor(node, AstarPath.active.debugPathData);
                            if (AstarPath.active.showSearchTree && (AstarPath.active.debugPathData != null))
                            {
                                if (base.InSearchTree(node, AstarPath.active.debugPath))
                                {
                                    PathNode pathNode = debugPathData.GetPathNode(node);
                                    if ((pathNode != null) && (pathNode.parent != null))
                                    {
                                        Gizmos.DrawLine((Vector3) node.position, (Vector3) pathNode.parent.node.position);
                                    }
                                }
                            }
                            else
                            {
                                for (int k = 0; k < 8; k++)
                                {
                                    GridNode nodeConnection = this.GetNodeConnection(node, k);
                                    if (nodeConnection != null)
                                    {
                                        Gizmos.DrawLine((Vector3) node.position, (Vector3) nodeConnection.position);
                                    }
                                }
                                if (node.connections != null)
                                {
                                    for (int m = 0; m < node.connections.Length; m++)
                                    {
                                        GraphNode node4 = node.connections[m];
                                        Gizmos.DrawLine((Vector3) node.position, (Vector3) node4.position);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        public void OnPostScan(AstarPath script)
        {
            AstarPath.OnPostScan = (OnScanDelegate) Delegate.Remove(AstarPath.OnPostScan, new OnScanDelegate(this.OnPostScan));
            if (this.autoLinkGrids && (this.autoLinkDistLimit > 0f))
            {
                throw new NotSupportedException();
            }
        }

        public override void PostDeserialization()
        {
            this.GenerateMatrix();
            this.SetUpOffsetsAndCosts();
            if ((this.nodes != null) && (this.nodes.Length != 0))
            {
                if ((this.width * this.depth) != this.nodes.Length)
                {
                    Debug.LogWarning("Node data did not match with bounds data. Probably a change to the bounds/width/depth data was made after scanning the graph just prior to saving it. Nodes will be discarded");
                    this.nodes = new GridNode[0];
                }
                else
                {
                    GridNode.SetGridGraph(AstarPath.active.astarData.GetGraphIndex(this), this);
                    for (int i = 0; i < this.depth; i++)
                    {
                        for (int j = 0; j < this.width; j++)
                        {
                            GridNode node = this.nodes[(i * this.width) + j];
                            if (node == null)
                            {
                                Debug.LogError("Deserialization Error : Couldn't cast the node to the appropriate type - GridGenerator. Check the CreateNodes function");
                                return;
                            }
                            node.NodeInGridIndex = (i * this.width) + j;
                        }
                    }
                }
            }
        }

        public void RemoveGridGraphFromStatic()
        {
            GridNode.SetGridGraph(AstarPath.active.astarData.GetGraphIndex(this), null);
        }

        public override void ScanInternal(OnScanStatus statusCallback)
        {
            AstarPath.OnPostScan = (OnScanDelegate) Delegate.Combine(AstarPath.OnPostScan, new OnScanDelegate(this.OnPostScan));
            this.scans++;
            if (this.nodeSize > 0f)
            {
                this.GenerateMatrix();
                if ((this.width > 0x400) || (this.depth > 0x400))
                {
                    Debug.LogError("One of the grid's sides is longer than 1024 nodes");
                }
                else
                {
                    this.SetUpOffsetsAndCosts();
                    int graphIndex = AstarPath.active.astarData.GetGraphIndex(this);
                    GridNode.SetGridGraph(graphIndex, this);
                    this.nodes = new GridNode[this.width * this.depth];
                    for (int i = 0; i < this.nodes.Length; i++)
                    {
                        this.nodes[i] = new GridNode(base.active);
                        this.nodes[i].GraphIndex = (uint) graphIndex;
                    }
                    if (this.collision == null)
                    {
                        this.collision = new GraphCollision();
                    }
                    this.collision.Initialize(base.matrix, this.nodeSize);
                    this.textureData.Initialize();
                    for (int j = 0; j < this.depth; j++)
                    {
                        for (int m = 0; m < this.width; m++)
                        {
                            GridNode node = this.nodes[(j * this.width) + m];
                            node.NodeInGridIndex = (j * this.width) + m;
                            this.UpdateNodePositionCollision(node, m, j, true);
                            this.textureData.Apply(node, m, j);
                        }
                    }
                    for (int k = 0; k < this.depth; k++)
                    {
                        for (int n = 0; n < this.width; n++)
                        {
                            GridNode node2 = this.nodes[(k * this.width) + n];
                            this.CalculateConnections(this.nodes, n, k, node2);
                        }
                    }
                    this.ErodeWalkableArea();
                }
            }
        }

        public override void SerializeExtraInfo(GraphSerializationContext ctx)
        {
            if (this.nodes == null)
            {
                ctx.writer.Write(-1);
            }
            else
            {
                ctx.writer.Write(this.nodes.Length);
                for (int i = 0; i < this.nodes.Length; i++)
                {
                    this.nodes[i].SerializeNode(ctx);
                }
            }
        }

        public void SetNodeConnection(GridNode node, int dir, bool value)
        {
            int nodeInGridIndex = node.NodeInGridIndex;
            int z = nodeInGridIndex / this.Width;
            int x = nodeInGridIndex - (z * this.Width);
            this.SetNodeConnection(nodeInGridIndex, x, z, dir, value);
        }

        public void SetNodeConnection(int index, int x, int z, int dir, bool value)
        {
            this.nodes[index].SetConnectionInternal(dir, value);
        }

        public virtual void SetUpOffsetsAndCosts()
        {
            this.neighbourOffsets[0] = -this.width;
            this.neighbourOffsets[1] = 1;
            this.neighbourOffsets[2] = this.width;
            this.neighbourOffsets[3] = -1;
            this.neighbourOffsets[4] = -this.width + 1;
            this.neighbourOffsets[5] = this.width + 1;
            this.neighbourOffsets[6] = this.width - 1;
            this.neighbourOffsets[7] = -this.width - 1;
            uint num = (uint) Mathf.RoundToInt(this.nodeSize * 1000f);
            uint num2 = (uint) Mathf.RoundToInt((this.nodeSize * Mathf.Sqrt(2f)) * 1000f);
            this.neighbourCosts[0] = num;
            this.neighbourCosts[1] = num;
            this.neighbourCosts[2] = num;
            this.neighbourCosts[3] = num;
            this.neighbourCosts[4] = num2;
            this.neighbourCosts[5] = num2;
            this.neighbourCosts[6] = num2;
            this.neighbourCosts[7] = num2;
            this.neighbourXOffsets[0] = 0;
            this.neighbourXOffsets[1] = 1;
            this.neighbourXOffsets[2] = 0;
            this.neighbourXOffsets[3] = -1;
            this.neighbourXOffsets[4] = 1;
            this.neighbourXOffsets[5] = 1;
            this.neighbourXOffsets[6] = -1;
            this.neighbourXOffsets[7] = -1;
            this.neighbourZOffsets[0] = -1;
            this.neighbourZOffsets[1] = 0;
            this.neighbourZOffsets[2] = 1;
            this.neighbourZOffsets[3] = 0;
            this.neighbourZOffsets[4] = -1;
            this.neighbourZOffsets[5] = 1;
            this.neighbourZOffsets[6] = 1;
            this.neighbourZOffsets[7] = -1;
        }

        public bool SnappedLinecast(Vector3 _a, Vector3 _b, GraphNode hint, out GraphHitInfo hit)
        {
            hit = new GraphHitInfo();
            GraphNode node = base.GetNearest(_a, NNConstraint.None).node;
            GraphNode node2 = base.GetNearest(_b, NNConstraint.None).node;
            _a = this.inverseMatrix.MultiplyPoint3x4((Vector3) node.position);
            _a.x -= 0.5f;
            _a.z -= 0.5f;
            _b = this.inverseMatrix.MultiplyPoint3x4((Vector3) node2.position);
            _b.x -= 0.5f;
            _b.z -= 0.5f;
            Int3 num = new Int3(Mathf.RoundToInt(_a.x), Mathf.RoundToInt(_a.y), Mathf.RoundToInt(_a.z));
            Int3 num2 = new Int3(Mathf.RoundToInt(_b.x), Mathf.RoundToInt(_b.y), Mathf.RoundToInt(_b.z));
            hit.origin = (Vector3) num;
            if (!this.nodes[(num.z * this.width) + num.x].Walkable)
            {
                hit.node = this.nodes[(num.z * this.width) + num.x];
                hit.point = this.matrix.MultiplyPoint3x4(new Vector3(num.x + 0.5f, 0f, num.z + 0.5f));
                Vector3 position = (Vector3) hit.node.position;
                hit.point.y = position.y;
                return true;
            }
            int num3 = Mathf.Abs((int) (num.x - num2.x));
            int num4 = Mathf.Abs((int) (num.z - num2.z));
            int num5 = 0;
            int num6 = 0;
            if (num.x < num2.x)
            {
                num5 = 1;
            }
            else
            {
                num5 = -1;
            }
            if (num.z < num2.z)
            {
                num6 = 1;
            }
            else
            {
                num6 = -1;
            }
            int num7 = num3 - num4;
            while ((num.x != num2.x) || (num.z != num2.z))
            {
                int num8 = num7 * 2;
                int num9 = 0;
                Int3 num10 = num;
                if (num8 > -num4)
                {
                    num7 -= num4;
                    num9 = num5;
                    num10.x += num5;
                }
                if (num8 < num3)
                {
                    num7 += num3;
                    num9 += this.width * num6;
                    num10.z += num6;
                }
                if (num9 == 0)
                {
                    Debug.LogError("Offset is zero, this should not happen");
                    return false;
                }
                for (int i = 0; i < this.neighbourOffsets.Length; i++)
                {
                    if (this.neighbourOffsets[i] == num9)
                    {
                        if (!this.CheckConnection(this.nodes[(num.z * this.width) + num.x], i))
                        {
                            hit.node = this.nodes[(num.z * this.width) + num.x];
                            hit.point = this.matrix.MultiplyPoint3x4(new Vector3(num.x + 0.5f, 0f, num.z + 0.5f));
                            Vector3 vector3 = (Vector3) hit.node.position;
                            hit.point.y = vector3.y;
                            return true;
                        }
                        if (!this.nodes[(num10.z * this.width) + num10.x].Walkable)
                        {
                            hit.node = this.nodes[(num.z * this.width) + num.x];
                            hit.point = this.matrix.MultiplyPoint3x4(new Vector3(num.x + 0.5f, 0f, num.z + 0.5f));
                            Vector3 vector2 = (Vector3) hit.node.position;
                            hit.point.y = vector2.y;
                            return true;
                        }
                        num = num10;
                        break;
                    }
                }
            }
            return false;
        }

        public void UpdateArea(GraphUpdateObject o)
        {
            if ((this.nodes == null) || (this.nodes.Length != (this.width * this.depth)))
            {
                Debug.LogWarning("The Grid Graph is not scanned, cannot update area ");
            }
            else
            {
                Vector3 vector;
                Vector3 vector2;
                Bounds b = o.bounds;
                this.GetBoundsMinMax(b, base.inverseMatrix, out vector, out vector2);
                int xmin = Mathf.RoundToInt(vector.x - 0.5f);
                int xmax = Mathf.RoundToInt(vector2.x - 0.5f);
                int ymin = Mathf.RoundToInt(vector.z - 0.5f);
                int ymax = Mathf.RoundToInt(vector2.z - 0.5f);
                IntRect a = new IntRect(xmin, ymin, xmax, ymax);
                IntRect rect2 = a;
                IntRect rect3 = new IntRect(0, 0, this.width - 1, this.depth - 1);
                IntRect rect4 = a;
                int range = !o.updateErosion ? 0 : this.erodeIterations;
                bool flag = o.updatePhysics || o.modifyWalkability;
                if ((o.updatePhysics && !o.modifyWalkability) && this.collision.collisionCheck)
                {
                    Vector3 vector3 = (Vector3) (new Vector3(this.collision.diameter, 0f, this.collision.diameter) * 0.5f);
                    vector -= (Vector3) (vector3 * 1.02f);
                    vector2 += (Vector3) (vector3 * 1.02f);
                    int introduced48 = Mathf.RoundToInt(vector.x - 0.5f);
                    int introduced49 = Mathf.RoundToInt(vector2.x - 0.5f);
                    rect4 = new IntRect(introduced48, Mathf.RoundToInt(vector.z - 0.5f), introduced49, Mathf.RoundToInt(vector2.z - 0.5f));
                    rect2 = IntRect.Union(rect4, rect2);
                }
                if (flag || (range > 0))
                {
                    rect2 = rect2.Expand(range + 1);
                }
                IntRect rect5 = IntRect.Intersection(rect2, rect3);
                for (int i = rect5.xmin; i <= rect5.xmax; i++)
                {
                    for (int k = rect5.ymin; k <= rect5.ymax; k++)
                    {
                        o.WillUpdateNode(this.nodes[(k * this.width) + i]);
                    }
                }
                if (o.updatePhysics && !o.modifyWalkability)
                {
                    this.collision.Initialize(base.matrix, this.nodeSize);
                    rect5 = IntRect.Intersection(rect4, rect3);
                    for (int m = rect5.xmin; m <= rect5.xmax; m++)
                    {
                        for (int n = rect5.ymin; n <= rect5.ymax; n++)
                        {
                            int index = (n * this.width) + m;
                            GridNode node = this.nodes[index];
                            this.UpdateNodePositionCollision(node, m, n, o.resetPenaltyOnPhysics);
                        }
                    }
                }
                rect5 = IntRect.Intersection(a, rect3);
                for (int j = rect5.xmin; j <= rect5.xmax; j++)
                {
                    for (int num12 = rect5.ymin; num12 <= rect5.ymax; num12++)
                    {
                        int num13 = (num12 * this.width) + j;
                        GridNode node2 = this.nodes[num13];
                        if (flag)
                        {
                            node2.Walkable = node2.WalkableErosion;
                            if (o.bounds.Contains((Vector3) node2.position))
                            {
                                o.Apply(node2);
                            }
                            node2.WalkableErosion = node2.Walkable;
                        }
                        else if (o.bounds.Contains((Vector3) node2.position))
                        {
                            o.Apply(node2);
                        }
                    }
                }
                if (flag && (range == 0))
                {
                    rect5 = IntRect.Intersection(rect2, rect3);
                    for (int num14 = rect5.xmin; num14 <= rect5.xmax; num14++)
                    {
                        for (int num15 = rect5.ymin; num15 <= rect5.ymax; num15++)
                        {
                            int num16 = (num15 * this.width) + num14;
                            GridNode node3 = this.nodes[num16];
                            this.CalculateConnections(this.nodes, num14, num15, node3);
                        }
                    }
                }
                else if (flag && (range > 0))
                {
                    IntRect rect6 = IntRect.Union(a, rect4).Expand(range);
                    IntRect rect7 = rect6.Expand(range);
                    rect6 = IntRect.Intersection(rect6, rect3);
                    rect7 = IntRect.Intersection(rect7, rect3);
                    for (int num17 = rect7.xmin; num17 <= rect7.xmax; num17++)
                    {
                        for (int num18 = rect7.ymin; num18 <= rect7.ymax; num18++)
                        {
                            int num19 = (num18 * this.width) + num17;
                            GridNode node4 = this.nodes[num19];
                            bool walkable = node4.Walkable;
                            node4.Walkable = node4.WalkableErosion;
                            if (!rect6.Contains(num17, num18))
                            {
                                node4.TmpWalkable = walkable;
                            }
                        }
                    }
                    for (int num20 = rect7.xmin; num20 <= rect7.xmax; num20++)
                    {
                        for (int num21 = rect7.ymin; num21 <= rect7.ymax; num21++)
                        {
                            int num22 = (num21 * this.width) + num20;
                            GridNode node5 = this.nodes[num22];
                            this.CalculateConnections(this.nodes, num20, num21, node5);
                        }
                    }
                    this.ErodeWalkableArea(rect7.xmin, rect7.ymin, rect7.xmax + 1, rect7.ymax + 1);
                    for (int num23 = rect7.xmin; num23 <= rect7.xmax; num23++)
                    {
                        for (int num24 = rect7.ymin; num24 <= rect7.ymax; num24++)
                        {
                            if (!rect6.Contains(num23, num24))
                            {
                                int num25 = (num24 * this.width) + num23;
                                GridNode node6 = this.nodes[num25];
                                node6.Walkable = node6.TmpWalkable;
                            }
                        }
                    }
                    for (int num26 = rect7.xmin; num26 <= rect7.xmax; num26++)
                    {
                        for (int num27 = rect7.ymin; num27 <= rect7.ymax; num27++)
                        {
                            int num28 = (num27 * this.width) + num26;
                            GridNode node7 = this.nodes[num28];
                            this.CalculateConnections(this.nodes, num26, num27, node7);
                        }
                    }
                }
            }
        }

        public void UpdateAreaInit(GraphUpdateObject o)
        {
        }

        public virtual void UpdateNodePositionCollision(GridNode node, int x, int z, bool resetPenalty = true)
        {
            RaycastHit hit;
            node.position = this.GetNodePosition(node.NodeInGridIndex, 0);
            bool walkable = true;
            Vector3 vector = this.collision.CheckHeight((Vector3) node.position, out hit, out walkable);
            node.position = (Int3) vector;
            if (resetPenalty)
            {
                node.Penalty = base.initialPenalty;
            }
            if (this.penaltyPosition && resetPenalty)
            {
                node.Penalty += (uint) Mathf.RoundToInt((node.position.y - this.penaltyPositionOffset) * this.penaltyPositionFactor);
            }
            if ((walkable && this.useRaycastNormal) && (this.collision.heightCheck && (hit.normal != Vector3.zero)))
            {
                float num = Vector3.Dot(hit.normal.normalized, this.collision.up);
                if (this.penaltyAngle && resetPenalty)
                {
                    node.Penalty += (uint) Mathf.RoundToInt((1f - num) * this.penaltyAngleFactor);
                }
                float num2 = Mathf.Cos(this.maxSlope * 0.01745329f);
                if (num < num2)
                {
                    walkable = false;
                }
            }
            if (walkable)
            {
                node.Walkable = this.collision.Check((Vector3) node.position);
            }
            else
            {
                node.Walkable = walkable;
            }
            node.WalkableErosion = node.Walkable;
        }

        public void UpdateSizeFromWidthDepth()
        {
            this.unclampedSize = (Vector2) (new Vector2((float) this.width, (float) this.depth) * this.nodeSize);
            this.GenerateMatrix();
        }

        public int Depth
        {
            get
            {
                return this.depth;
            }
            set
            {
                this.depth = value;
            }
        }

        public virtual bool uniformWidthDepthGrid
        {
            get
            {
                return true;
            }
        }

        public bool useRaycastNormal
        {
            get
            {
                return (Math.Abs((float) (90f - this.maxSlope)) > float.Epsilon);
            }
        }

        public int Width
        {
            get
            {
                return this.width;
            }
            set
            {
                this.width = value;
            }
        }

        public class TextureData
        {
            public ChannelUse[] channels = new ChannelUse[3];
            private Color32[] data;
            public bool enabled;
            public float[] factors = new float[3];
            public Texture2D source;

            public void Apply(GridNode node, int x, int z)
            {
                if ((this.enabled && (this.data != null)) && ((x < this.source.width) && (z < this.source.height)))
                {
                    Color32 color = this.data[(z * this.source.width) + x];
                    if (this.channels[0] != ChannelUse.None)
                    {
                        this.ApplyChannel(node, x, z, color.r, this.channels[0], this.factors[0]);
                    }
                    if (this.channels[1] != ChannelUse.None)
                    {
                        this.ApplyChannel(node, x, z, color.g, this.channels[1], this.factors[1]);
                    }
                    if (this.channels[2] != ChannelUse.None)
                    {
                        this.ApplyChannel(node, x, z, color.b, this.channels[2], this.factors[2]);
                    }
                }
            }

            private void ApplyChannel(GridNode node, int x, int z, int value, ChannelUse channelUse, float factor)
            {
                switch (channelUse)
                {
                    case ChannelUse.Penalty:
                        node.Penalty += (uint) Mathf.RoundToInt(value * factor);
                        break;

                    case ChannelUse.Position:
                        node.position = GridNode.GetGridGraph(node.GraphIndex).GetNodePosition(node.NodeInGridIndex, Mathf.RoundToInt((value * factor) * 1000f));
                        break;

                    case ChannelUse.WalkablePenalty:
                        if (value != 0)
                        {
                            node.Penalty += (uint) Mathf.RoundToInt((value - 1) * factor);
                            break;
                        }
                        node.Walkable = false;
                        break;
                }
            }

            public void Initialize()
            {
                if (this.enabled && (this.source != null))
                {
                    for (int i = 0; i < this.channels.Length; i++)
                    {
                        if (this.channels[i] != ChannelUse.None)
                        {
                            try
                            {
                                this.data = this.source.GetPixels32();
                            }
                            catch (UnityException exception)
                            {
                                Debug.LogWarning(exception.ToString());
                                this.data = null;
                            }
                            break;
                        }
                    }
                }
            }

            public enum ChannelUse
            {
                None,
                Penalty,
                Position,
                WalkablePenalty
            }
        }
    }
}

